﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using AGMLite.Windows.Notify;
using System.Windows;
using Hardcodet.Wpf.TaskbarNotification;
using System.Windows.Controls.Primitives;
using HPAGMRestAPIWrapper;
using System.Diagnostics;
using System.Windows.Threading;
using System.Threading;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using AGMLite.UserControl;
using AGMLite.Common;
using System.Net;
using System.Windows.Media;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using AGMLite.Windows;

namespace AGMLite.BaseClass
{
    public class AGMLiteEntity : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        #region Public Properties
        public TaskbarIcon TaskBarIcon { get; set; }
        public int BallonStaySeconds { get; set; }
        public Common.AGMLiteEnum.EntityType EntityType { get; set; }
        public AGMProject Project { get; set; }
        public AGMEntity Entity { get; set; }
        public Dictionary<int, AGMField> ViewFields { get; set; }        

        public bool IsNew
        {
            get
            {
                return _isNew;
            }
            set
            {
                if (value != _isNew)
                {
                    _isNew = value;
                    OnPropertyChanged("IsNew");
                }
            }
        }

        /// <summary>
        /// Health, 0 - health, 1- warn, 2 - problem
        /// </summary>
        public int Health
        {
            get
            {
                return _health;
            }
            set
            {
                if (value != _health)
                {
                    _health = value;
                    OnPropertyChanged("Health");
                }
            }
        }

        public string HealthMessage
        {
            get
            {
                return _healthMessage;
            }
            set
            {
                if (value != _healthMessage)
                {
                    _healthMessage = value;
                    OnPropertyChanged("HealthMessage");
                }
            }
        }

        public string Id
        {
            get
            {
                return _id;
            }
            set
            {
                if (value != _id)
                {
                    _id = value;
                    OnPropertyChanged("Id");
                }
            }
        }

        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                if (value != _name)
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
        }

        public string Description
        {
            get
            {
                return _description;
            }
            set
            {
                if (value != _description)
                {
                    _description = value;
                    OnPropertyChanged("Description");
                }
            }
        }

        public EntityDetailUserControl EntityDetailControl
        {
            get
            {
                return _entityDetailControl;
            }
            set
            {
                if (value != _entityDetailControl)
                {
                    _entityDetailControl = value;
                    OnPropertyChanged("EntityDetailControl");
                }
            }
        }

        #endregion 

        #region private members
        private bool _isNew;
        private int _health;
        private string _id;
        private string _name;
        private string _description;
        private string _healthMessage;
        private EntityDetailUserControl _entityDetailControl;

        private BackgroundWorker _bgWorker;
        private Window entityDetailWindow;
        #endregion

        public AGMLiteEntity()
        {
        }

        #region Public Methods
        public void ShowNewItemMessage(string itemName)
        {
            string iconpath = null;
            string text = null;
            string entityId = null;

            try
            {
                entityId = Entity.Id.Value.ToString();
                switch (EntityType)
                {
                    case Common.AGMLiteEnum.EntityType.Requirement:
                        iconpath = @"/images/req.png";
                        text = Entity.GetField("name").Value;
                        break;
                    case Common.AGMLiteEnum.EntityType.Defect:
                        iconpath = @"/images/bug.png";
                        text = Entity.GetField("name").Value;
                        break;
                    case Common.AGMLiteEnum.EntityType.ProjectTask:
                        iconpath = @"/images/task.png";
                        text = Entity.GetField("description").Value;
                        break;
                }
                int sec = BallonStaySeconds == 0 ? 5 : BallonStaySeconds * 1000;
                FancyBalloon balloon = new FancyBalloon();
                balloon.BalloonTitle = itemName;
                balloon.BalloonText = text.Length > 100 ? string.Format("{0}...", text.Substring(0, 100)) : string.Format("{0}", text);
                balloon.BalloonIcon = iconpath;
                balloon.BalloonSubTitle = string.Format("1 new {0}: {1}", EntityType.ToString(), entityId);
                balloon.DoubleClickEvent += new RoutedEventHandler(balloon_DoubleClickEvent);
                //show balloon and close it after 5 seconds
                TaskBarIcon.ShowCustomBalloon(balloon, PopupAnimation.Slide, sec);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }        
        }

        public void OpenEntityPage()
        {
            string url = GetEntityLink();
            if (!string.IsNullOrEmpty(url))
                Process.Start(url);
        }

        public string GetEntityLink()
        {
            string entityURL = null;

            if (EntityType == Common.AGMLiteEnum.EntityType.ProjectTask)
            {
                string entityId = null;
                string entitytype = null;

                HPAGMRestAPIWrapper.AGMProjectTasks tasks = new AGMProjectTasks(Project.Connection);
                var task = tasks.Get(Entity.Id.Value);
                HPAGMRestAPIWrapper.AGMReleaseBacklogItems backlogItems = new AGMReleaseBacklogItems(Project.Connection);
                List<AGMField> filter = new List<AGMField>();
                filter.Add(new AGMField { Name = "id", Value = task.GetField("release-backlog-item-id").Value });
                var backlogItemResult = backlogItems.GetCollection(filter);
                if (backlogItemResult.Count > 0)
                {
                    entitytype = backlogItemResult[0].GetField("entity-type").Value;
                    entityId = backlogItemResult[0].GetField("entity-id").Value;

                    entityURL = string.Format(
                    "{0}/agm/webui/alm/{1}/{2}/apm/?TENANTID={3}#product/backlog_items/shared.update;entityTypeName={4};entityId={5}&@content;currentTabId=com.hp.alm.core.client.details.tab.overview.OverviewTabItem",
                    Project.Server,
                    Project.Domain,
                    Project.Project,
                    Project.Domain.Substring(1, Project.Domain.IndexOf("_") - 1),
                    entitytype,
                    entityId);
                }
                else
                    MessageBox.Show("Cannot find requirement or defect which related to this task.");                
            }
            else
            {
                entityURL = string.Format(
                "{0}/agm/webui/alm/{1}/{2}/apm/?TENANTID={3}#product/backlog_items/shared.update;entityTypeName={4};entityId={5}&@content;currentTabId=com.hp.alm.core.client.details.tab.overview.OverviewTabItem",
                Project.Server,
                Project.Domain,
                Project.Project,
                Project.Domain.Substring(1, Project.Domain.IndexOf("_") - 1),
                EntityType.ToString().ToLower(),
                Entity.Id.ToString());
            }

            return entityURL;            
        }

        private UIElement AddFieldControl(string label, string value)
        {
            Border fieldBorder = new Border()
            {
                CornerRadius = new CornerRadius(3),
                BorderThickness = new Thickness(1),
                BorderBrush = new SolidColorBrush(Colors.Gray),
                Margin = new Thickness(2),
            };

            StackPanel fieldStackPanel = new StackPanel()
            {
                Orientation = Orientation.Horizontal,
            };

            Label fieldLabel = new Label()
            {
                Content = label,
                Margin = new Thickness(2),
                VerticalAlignment = VerticalAlignment.Top,
                FontWeight = FontWeights.Bold,
                Width = 180,
            };

            string valueText = StripText(value).Trim();
            TextBlock fieldTextBlock = new TextBlock()
            {
                TextWrapping = TextWrapping.Wrap,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Center,
                Text = valueText,
                Margin = new Thickness(2),
                Width = 550,
            };

            if (string.IsNullOrEmpty(valueText))
                fieldTextBlock.Background = Brushes.Red;

            fieldStackPanel.Children.Add(fieldLabel);
            fieldStackPanel.Children.Add(fieldTextBlock);
            fieldBorder.Child = fieldStackPanel;
            
            return fieldBorder;
        }

        private string GetFieldDisplayValue(AGMField field)
        {
            string fieldvalue = null;

            if (field.Options != null)
            {
                if (field.Options.Count > 0)
                {
                    fieldvalue = field.Options[field.Value];
                }
                else
                {
                    fieldvalue = field.Value;
                }
            }
            else
            {
                fieldvalue = field.Value;
            }

            return fieldvalue;
        }

        public void OpenEntityDetail()
        {
            _bgWorker = new BackgroundWorker();
            _bgWorker.DoWork += new DoWorkEventHandler(Prepare_DoWork);
            _bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Prepare_RunWorkerCompleted);
            _bgWorker.RunWorkerAsync();            
        }

        private void Prepare_DoWork(object sender, DoWorkEventArgs e)
        {
            Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, (ThreadStart)delegate
            {
                BuildEntityDetailControlWithProgressBar();
                entityDetailWindow = new Window()
                {
                    Content = EntityDetailControl,
                    Width = 800,
                    MinHeight = 200,
                    MaxHeight = 800,
                    SizeToContent = System.Windows.SizeToContent.Height,
                    WindowStartupLocation = WindowStartupLocation.CenterScreen,
                    Title = string.Format("{0} - {1}", Id, Name),
                    Icon = new BitmapImage(new Uri("pack://application:,,,/AGMLite;component/images/agm.ico")),                    
                };
                entityDetailWindow.Show();
                entityDetailWindow.WindowState = WindowState.Normal;
                entityDetailWindow.Activate();
            });
            FillFields(ViewFields);
        }

        private void Prepare_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            BuildEntityDetailControl();

            entityDetailWindow.Content = EntityDetailControl;
        }

        public void BuildEntityDetailControlWithProgressBar()
        {
            EntityDetailUserControl educ = new EntityDetailUserControl();

            StackPanel mainStackPanel = new StackPanel()
            {
                Orientation = Orientation.Vertical,
                Margin = new Thickness(5),
            };

            TextBlock loadingTB = new TextBlock()
            {
                Text = "Loading..., please be patient.",
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center,
                FontSize = 18,
                FontWeight = FontWeights.Bold,
                Margin = new Thickness(5),
            };

            ProgressBar pBar = new ProgressBar()
            {
                Width=400,
                Height = 20,
                IsIndeterminate = true,
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center,
                Margin = new Thickness(5),
            };

            mainStackPanel.Children.Add(loadingTB);
            mainStackPanel.Children.Add(pBar);

            educ.Content = mainStackPanel;
            EntityDetailControl = educ;
        }

        public void BuildEntityDetailControl()
        {
            EntityDetailUserControl educ = new EntityDetailUserControl();

            ScrollViewer scrollViewer = new ScrollViewer()
            {
                IsDeferredScrollingEnabled = true,
                HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
                VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Stretch,
            };

            StackPanel mainStackPanel = new StackPanel()
            {
                Orientation = Orientation.Vertical,
                Margin = new Thickness(5),
            };

            #region Build Detail Pane
            GroupBox entityGroupBox = new GroupBox()
            {
                Header = "Detail",
                VerticalAlignment = VerticalAlignment.Stretch,
                HorizontalAlignment = HorizontalAlignment.Stretch,
            };

            StackPanel entityStackPanel = new StackPanel()
            {
                Orientation = Orientation.Vertical,
                Margin = new Thickness(1), 
            };

            foreach(KeyValuePair<int, AGMField> viewfield in ViewFields.OrderBy(p=>p.Key).Where(o=> Entity.Fields.Where(k=>k.Name.Equals(o.Value.Name) && k.Entity.Equals(o.Value.Entity)).Count() == 1))
            {
                AGMField field = Entity.Fields.Where(k=>k.Name.Equals(viewfield.Value.Name) && k.Entity.Equals(viewfield.Value.Entity)).Single() as AGMField;
                var fieldctrl = AddFieldControl(field.Label, GetFieldDisplayValue(field));
                entityStackPanel.Children.Add(fieldctrl);
            }

            //foreach (AGMField field in Entity.Fields.Where(o => o.Active && o.Visible && ViewFields.OrderBy(k=>k.Key).Where(p => p.Value.Name.Equals(o.Name) && p.Value.Entity.Equals(o.Entity)).Count() == 1))
            //{
            //    var fieldctrl = AddFieldControl(field.Label, GetFieldDisplayValue(field));
            //    entityStackPanel.Children.Add(fieldctrl);
            //}

            entityGroupBox.Content = entityStackPanel;
            #endregion

            #region Build release plan Pane
            GroupBox backlogGroupBox = new GroupBox()
            {
                Header = "Release Plan",
                VerticalAlignment = VerticalAlignment.Stretch,
                HorizontalAlignment = HorizontalAlignment.Stretch,
            };

            StackPanel backlogStackPanel = new StackPanel()
            {
                Orientation = Orientation.Vertical,
                Margin = new Thickness(1),
            };

            if (EntityType == AGMLiteEnum.EntityType.Requirement)
            {
                AGMRequirement requirement = Entity as AGMRequirement;
                foreach(KeyValuePair<int, AGMField> viewfield in ViewFields.OrderBy(p=>p.Key).Where(o=> requirement.BacklogItem.Fields.Where(k=>k.Name.Equals(o.Value.Name) && k.Entity.Equals(o.Value.Entity)).Count() == 1))
                {
                    AGMField field = requirement.BacklogItem.Fields.Where(k => k.Name.Equals(viewfield.Value.Name) && k.Entity.Equals(viewfield.Value.Entity)).Single() as AGMField;
                    var fieldctrl = AddFieldControl(field.Label, GetFieldDisplayValue(field));
                    backlogStackPanel.Children.Add(fieldctrl);
                }

                //foreach (AGMField field in requirement.BacklogItem.Fields.Where(o => o.Active && o.Visible && ViewFields.OrderBy(k => k.Key).Where(p => p.Value.Name.Equals(o.Name) && p.Value.Entity.Equals(o.Entity)).Count() == 1))
                //{
                //    var fieldctrl = AddFieldControl(field.Label, GetFieldDisplayValue(field));
                //    backlogStackPanel.Children.Add(fieldctrl);
                //}
            }
            else if (EntityType == AGMLiteEnum.EntityType.Defect)
            {
                AGMDefect defect = Entity as AGMDefect;
                foreach (KeyValuePair<int, AGMField> viewfield in ViewFields.OrderBy(p => p.Key).Where(o => defect.BacklogItem.Fields.Where(k => k.Name.Equals(o.Value.Name) && k.Entity.Equals(o.Value.Entity)).Count() == 1))
                {
                    AGMField field = defect.BacklogItem.Fields.Where(k => k.Name.Equals(viewfield.Value.Name) && k.Entity.Equals(viewfield.Value.Entity)).Single() as AGMField;
                    var fieldctrl = AddFieldControl(field.Label, GetFieldDisplayValue(field));
                    backlogStackPanel.Children.Add(fieldctrl);
                }

                //foreach (AGMField field in defect.BacklogItem.Fields.Where(o => o.Active && o.Visible && ViewFields.OrderBy(k => k.Key).Where(p => p.Value.Name.Equals(o.Name) && p.Value.Entity.Equals(o.Entity)).Count() == 1))
                //{
                //    var fieldctrl = AddFieldControl(field.Label, GetFieldDisplayValue(field));
                //    backlogStackPanel.Children.Add(fieldctrl);
                //}
            }
            backlogGroupBox.Content = backlogStackPanel;
            #endregion

            mainStackPanel.Children.Add(entityGroupBox);
            mainStackPanel.Children.Add(backlogGroupBox);

            scrollViewer.Content = mainStackPanel;
            educ.Content = scrollViewer;
            EntityDetailControl = educ;
        }

        public void FillFields(Dictionary<int, AGMField> viewFields)
        {
            List<string> entityFields = new List<string>();
            List<string> backlogItemFields = new List<string>();
            List<AGMField> filters = new List<AGMField>();

            switch (EntityType)
            {
                case AGMLiteEnum.EntityType.Requirement:
                    foreach (KeyValuePair<int, AGMField> vf in viewFields)
                    {
                        if (vf.Value.Entity.Equals("requirement"))
                        {
                            entityFields.Add(vf.Value.Name);
                        }
                        else if (vf.Value.Entity.Equals("release-backlog-item"))
                        {
                            backlogItemFields.Add(vf.Value.Name);
                        }
                    }
                    AGMRequirements reqs = new AGMRequirements(Entity.Connection);
                    filters.Add(new AGMField { Name="id", Value=Entity.Id.Value.ToString(), Entity="requirement" });
                    var reqcollection = reqs.GetCollection(filters, entityFields.ToArray());
                    if (reqcollection != null)
                    {
                        if (reqcollection.Count == 1)
                        {
                            var req = reqcollection[0];
                            foreach (AGMField field in req.Fields.Where(o=>!string.IsNullOrEmpty(o.Value)))
                            {
                                field.Options = field.GetOptions();
                            }
                            if (backlogItemFields.Count > 0)
                            {
                                req.GetReleaseBacklogItem(backlogItemFields.ToArray());
                                foreach (AGMField field in req.BacklogItem.Fields.Where(o => !string.IsNullOrEmpty(o.Value)))
                                {
                                    field.Options = field.GetOptions();
                                }
                            }                                
                            Entity = req;
                        }
                    } 
                    break;
                case AGMLiteEnum.EntityType.Defect:
                    foreach (KeyValuePair<int, AGMField> vf in viewFields)
                    {
                        if (vf.Value.Entity.Equals("defect"))
                        {
                            entityFields.Add(vf.Value.Name);
                        }
                        else if (vf.Value.Entity.Equals("release-backlog-item"))
                        {
                            backlogItemFields.Add(vf.Value.Name);
                        }
                    }
                    AGMDefects bugs = new AGMDefects(Entity.Connection);  
                    filters.Add(new AGMField { Name="id", Value=Entity.Id.Value.ToString(), Entity="defect" });
                    var bugcollection = bugs.GetCollection(filters, entityFields.ToArray());
                    if (bugcollection != null)
                    {
                        if (bugcollection.Count == 1)
                        {
                            var bug = bugcollection[0];
                            foreach (AGMField field in bug.Fields.Where(o => !string.IsNullOrEmpty(o.Value)))
                            {
                                field.Options = field.GetOptions();
                            }
                            if (backlogItemFields.Count > 0)
                            {
                                bug.GetReleaseBacklogItem(backlogItemFields.ToArray());
                                foreach (AGMField field in bug.BacklogItem.Fields.Where(o => !string.IsNullOrEmpty(o.Value)))
                                {
                                    field.Options = field.GetOptions();
                                }
                            }                                
                            Entity = bug;
                        }
                    }                    
                    break;
                case AGMLiteEnum.EntityType.ProjectTask:
                    foreach (KeyValuePair<int, AGMField> vf in viewFields)
                    {
                        entityFields.Add(vf.Value.Name);
                    }
                    AGMProjectTasks tasks = new AGMProjectTasks(Entity.Connection);                    
                    filters.Add(new AGMField { Name="id", Value=Entity.Id.Value.ToString(), Entity="project-task" });
                    var taskcollection = tasks.GetCollection(filters, entityFields.ToArray());
                    if (taskcollection != null)
                    {
                        if (taskcollection.Count == 1)
                        {
                            var task = taskcollection[0];
                            foreach (AGMField field in task.Fields.Where(o => !string.IsNullOrEmpty(o.Value)))
                            {
                                field.Options = field.GetOptions();
                            }
                            Entity = task;
                        }
                    }
                    break;
            }
        }
        
        #endregion
        
        #region Private methods
        private string StripText(string str)
        {
            string text = null;

            if (string.IsNullOrEmpty(str))
                return string.Empty;

            text = str.ToString().Replace("<br/>", Environment.NewLine).Replace("<br />", Environment.NewLine);
            text = text.Replace("</p>", Environment.NewLine);
            text = text.Replace("<li>", " - ");

            text = TextHelper.StripHTML(WebUtility.HtmlDecode(text)).Trim();

            return text;
        }

        private void balloon_DoubleClickEvent(object sender, RoutedEventArgs e)
        {
            OpenEntityPage();
            IsNew = false;
        }

        #region INotifyPropertyChanged Members
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
        #endregion
    }
}
